#include "GameNode.hpp"
#include "HotSpot.hpp"
#include "Action.hpp"
#include "Inventory.hpp"
#include "GameContext.hpp"
#include "GameLoop.hpp"
#include "TerminalView.hpp"
#include "HotSpotManager.hpp"

#include <string>
#include <memory>
#include <utility>

using namespace backpack;
using namespace std;


int main(void) {

  Inventory inventory;
  ExtendedGameContext gameContext(inventory);

  TerminalView view(cin, cout);
  GameLoop<TerminalView> gameLoop(gameContext, inventory, view);

  // game nodes
  GameNode corridor("Corridor", "long corridor", "in");
  GameNode kitchen("Kitchen", "messy kithen", "in");
  GameNode coldRoom("Cold Room", "small, cold room with lots of shelves "
      "and boxes\nthere is nothing interesting in here", "in a");
  GameNode livingRoom("Living Room", "large empty room with wooden floor","in");
  GameNode basement("Basement", "dark basement full of spider web", "in a");
  GameNode stairway1("Stairway 1st Floor", "wide corridor", "in");
  GameNode stairway2("Stairway 2nd Floor", "wide corridor", "in");
  GameNode bathroom("Bathroom", "bathroom", "in a");
  GameNode toilet("Toilet", "toilet", "in the");
  GameNode bedRoom("Bedroom", "room with purple walls", "in a");

  // items
  Key kitchenKey("Kitchen door key", "Very old looking key");
  Key stairwayKey("Stairway key", "Brass key");
  Key bedroomKey("Bedroom key", "Golden key");

  HotSpotManager hotSpotMgr;

  // corridor hotspots
  corridor.addHotSpot(
      hotSpotMgr.newDoor("metal door")
      .withDescription("heavy door in the north")
      .withLocation("at the end of the corridor (you think it's north)")
      );
  corridor.addHotSpot(
      hotSpotMgr.newDoor("door in the west")
      .withDescription("wooden door")
      .withLocation("on the west wall")
      .withTargetNode(kitchen)
      .unlockedWith(
        hotSpotMgr.newKeyHole(kitchenKey)
        ));
  corridor.addHotSpot(
      hotSpotMgr.newDoor("door in the east")
      .withDescription("another wooden door")
      .withLocation("on the east wall")
      .withTargetNode(livingRoom)
      .unlocked()
      );
  HotSpotVariant hiddenStairs = hotSpotMgr.newDoor("to the basement [NEW!]")
    .withDescription("a hole in the wall\n  and spiral stairs down")
    .withLocation("at the south end of the corridor")
    .withTargetNode(basement)
    .withChoice("go down")
    .unlocked()
    .invisible();
  corridor.addHotSpot(hiddenStairs);

  // living room hotspots
  livingRoom.addHotSpot(
      hotSpotMgr.newChest("weird casket")
      .withDescription("weird small casket")
      .withLocation("on the floor in the center of the room")
      .withItem(kitchenKey)
      .unlocked()
      );
  livingRoom.addHotSpot(
      hotSpotMgr.newDoor("door on the left")
      .withDescription("another wooden door")
      .withLocation("on your left")
      .withTargetNode(stairway1)
      .unlockedWith(
        hotSpotMgr.newKeyHole(stairwayKey)
        ));
  livingRoom.addHotSpot(
      hotSpotMgr.newDoor("to the corridor")
      .withDescription("wooden door that you came in")
      .withLocation("behind your back")
      .withChoice("go back")
      .withTargetNode(corridor)
      .unlocked()
      );

  // kitchen hotspots
  HotSpotVariant hiddenLever = hotSpotMgr.newLever("rusty lever [NEW!]")
    .withDescription("rusty lever")
    .withLocation("inside the cabinet on the wall")
    .switchesVisibilityOf(hiddenStairs,
        "you heard a scrappy noise in the corridor")
    .invisible();
  kitchen.addHotSpot(hiddenLever);
  kitchen.addHotSpot(
      hotSpotMgr.newLever("hanging cabinet")
      .withDescription("hanging cabinet")
      .withLocation("on the south wall")
      .withChoice("open")
      .shows(hiddenLever, "there is a rusty lever inside the cabinet")
      .oneShot()
      );
  kitchen.addHotSpot(
      hotSpotMgr.newDoor("heavy door")
      .withDescription("heavy door with a viewing window\n"
        "  it looks like a giant refridgerator")
      .withLocation("on the north wall")
      .withTargetNode(coldRoom)
      .unlocked()
      );
  kitchen.addHotSpot(
      hotSpotMgr.newDoor("to the corridor")
      .withDescription("wooden door that you came in")
      .withLocation("behind your back")
      .withChoice("go back")
      .withTargetNode(corridor)
      .unlocked()
      );

  // cold room hotspots
  coldRoom.addHotSpot(
      hotSpotMgr.newDoor("to the kitchen")
      .withDescription("heavy door that you came in")
      .withLocation("behind your back")
      .withChoice("go back")
      .withTargetNode(kitchen)
      .unlocked()
      );

  // basement hotspots
  basement.addHotSpot(
      hotSpotMgr.newDoor("upstairs")
      .withDescription("spiral stairs that you came down")
      .withLocation("behind your back")
      .withChoice("go back")
      .withTargetNode(corridor)
      .unlocked()
      );
  basement.addHotSpot(
      hotSpotMgr.newChest("the spider web")
      .withDescription("nothing, just web everywhere...")
      .withLocation("in front")
      .withChoice("search")
      .withItem(stairwayKey)
      .unlocked()
      );

  // stairway 1st floor hotspots
  stairway1.addHotSpot(
      hotSpotMgr.newDoor("upstairs")
      .withDescription("stairs up to 2nd floor")
      .withLocation("along the south wall")
      .withChoice("go")
      .withTargetNode(stairway2)
      .unlocked()
      );
  stairway1.addHotSpot(
      hotSpotMgr.newDoor("toilet")
      .withDescription("door with a label \"TOILET\"")
      .withLocation("on the north wall")
      .withChoice("go into the")
      .withTargetNode(toilet)
      .unlocked()
      );
  stairway1.addHotSpot(
      hotSpotMgr.newDoor("living room")
      .withDescription("the door to the living room")
      .withLocation("on the east wall")
      .withChoice("go back to")
      .withTargetNode(livingRoom)
      .unlocked()
      );

  // toilet
  toilet.addHotSpot(
      hotSpotMgr.newLever("")
      .withDescription("shiny toilet seat")
      .withLocation("in front of you")
      .withChoice("take a piss")
      .showsMessage("aaaaah... you feel a releaf")
      );
  toilet.addHotSpot(
      hotSpotMgr.newDoor("stairway")
      .withDescription("a door you came in here")
      .withLocation("behind your back")
      .withChoice("go back to the")
      .withTargetNode(stairway1)
      .unlocked()
      );

  // stairway 2nd floor hotspots
  stairway2.addHotSpot(
      hotSpotMgr.newDoor("bathroom")
      .withDescription("door with a label \"BATHROOM\"")
      .withLocation("on the north wall")
      .withChoice("go into the")
      .withTargetNode(bathroom)
      .unlocked()
      );
  stairway2.addHotSpot(
      hotSpotMgr.newDoor("door on the east wall")
      .withDescription("wooden door")
      .withLocation("on the east wall")
      .withTargetNode(bedRoom)
      .unlockedWith(
        hotSpotMgr.newKeyHole(bedroomKey)
        ));
  stairway2.addHotSpot(
      hotSpotMgr.newDoor("downstairs")
      .withDescription("stairs down to 1st floor")
      .withLocation("along the south wall")
      .withChoice("go")
      .withTargetNode(stairway1)
      .unlocked()
      );

  // bathroom hotspots
  bathroom.addHotSpot(
      hotSpotMgr.newLever("mirror")
      .withDescription("a mirror")
      .withLocation("in front")
      .withChoice("look in the")
      .showsMessage("you look very tired...")
      );
  bathroom.addHotSpot(
      hotSpotMgr.newChest("bathtub")
      .withDescription("a bathtub full of dark liquid, cork seem to be stuck")
      .withLocation("on the right")
      .withChoice("search the")
      .withItem(bedroomKey)
      .unlocked()
      );
  bathroom.addHotSpot(
      hotSpotMgr.newDoor("stairway")
      .withDescription("a door you came in here")
      .withLocation("behind your back")
      .withChoice("go back to the")
      .withTargetNode(stairway2)
      .unlocked()
      );

  // bedroom hotspots
  bedRoom.addHotSpot(
      hotSpotMgr.newLever("")
      .withDescription("large bed")
      .withLocation("in front")
      .withChoice("take a nap")
      .showsMessage("at last you've got some rest")
      .endsGame()
      );
  bedRoom.addHotSpot(
      hotSpotMgr.newDoor("stairway")
      .withDescription("a door you came in here")
      .withLocation("behind your back")
      .withChoice("go back to the")
      .withTargetNode(stairway2)
      .unlocked()
      );

  // start the game
  view.clearScreen()
    .showMessage("you need to get some sleep\nfind a bed and take a nap...");
  gameLoop.loop(corridor);

  view.printLine("game over");
}


